📝 Резюме · 🧾 Транскрипт (формат) · 📄 Оригинал (19.3 KB)
https://x.com/dhh/status/2033580762402902188

Пересказ: ONCE is back! It's now a full-fledged application server for running dockerized

Источник: https://x.com/dhh/status/2033580762402902188

Введение

ONCE — это революционный сервер приложений для запуска нескольких контейнеризованных веб-приложений на локальной машине, домашнем сервере, в облаке или на локальной инфраструктуре. Инструмент был создан для упрощения развертывания и управления приложениями, изначально разработанный для хостинга WriteBook, Campfire и Fizzy на одной машине. С развитием AI-кодирования (Vibe-кодирование) ONCE стал идеальной платформой для развертывания экспериментов, созданных с помощью ИИ, с единой точкой мониторинга, отслеживания ошибок, проверки емкости сервера и выполнения резервных копий без простоев.


Установка и базовая конфигурация

Процесс установки

ONCE устанавливается с помощью простой команды curl, которая автоматически обнаруживает систему и выполняет необходимые настройки. Единственное требование — наличие Docker. На Linux машинах, если Docker не установлен, ONCE установит его автоматически.

При первом запуске пользователю предлагается выбрать из трех встроенных приложений:

  • Campfire — чат-приложение для командного общения
  • Fizzy — доска Kanban для управления задачами
  • WriteBook — платформа для создания и обмена инструкциями и документацией

Кроме предустановленных приложений, поддерживается установка пользовательских Docker-образов.

Локальная установка Campfire

При настройке Campfire локально (на адресе chat.localhost) ONCE загружает Docker-образ из своего репозитория. После установки отображается основная панель управления с информацией о ресурсах машины:

  • Использование процессора (CPU)
  • Потребление оперативной памяти (RAM)
  • Доступное дисковое пространство

Приложение становится готовым к использованию сразу после установки. Пользователь регистрируется, указывая имя, электронную почту и пароль, и может начать использование приложения.


Развертывание нескольких приложений

Одновременный запуск нескольких сервисов

Главная магия ONCE заключается в управлении несколькими приложениями на одной машине. Пользователь может легко добавлять новые приложения, используя команду для добавления нового приложения (N).

WriteBook устанавливается похожим образом (например, на books.localhost.com) и разделяет аналогичный интерфейс входа с Campfire, но предоставляет функциональность создания и управления книгами.

Fizzy отличается тем, что требует настройки внешних сервисов. Для отправки электронных писем из Fizzy необходимо сконфигурировать SMTP-сервер (Postmark или аналогичный) через раздел настроек (S → E для email).

На одной локальной машине можно одновременно запускать все три приложения, и ONCE управляет их ресурсами и мониторингом.


Поддержка пользовательских приложений

Гибкость стека технологий

ONCE поддерживает любой стек технологий, несмотря на то, что встроенные приложения (WriteBook, Campfire, Fizzy) написаны на Ruby on Rails. Платформа может запускать приложения, написанные на:

  • Go
  • JavaScript/Node.js
  • Другие языки программирования

Демонстрация с Go и HTML5

В демонстрации показано создание простой wiki на Go с использованием SQLite. Приложение:

  • Упаковано в Docker-контейнер
  • Использует файловое хранилище для базы данных (storage)
  • Отвечает на запросы /up с кодом 200 OK — критический параметр для ONCE, обозначающий готовность приложения принимать запросы

Важный момент: ONCE использует /up endpoint для определения момента обновления приложения без потери запросов (zero-downtime updates).

Дополнительно продемонстрирована простая игра "Snake" на чистом HTML5 с визуализацией на базе единого HTML файла, запущенная в Nginx контейнере. Это демонстрирует, что ONCE поддерживает не только динамические приложения, но и статические веб-приложения.


Развертывание в облаке

Облачная установка на Hetzner VM

Процесс установки ONCE на облачном сервере (Hetzner VM) идентичен локальной установке — та же команда curl для Linux. Для полноценного использования используется:

  • Cloudflare для управления DNS
  • Wildcard домены (например, *.amaros.io) для маршрутизации на облачный IP

Развертывание приложений в облаке

На облачном сервере процесс аналогичен локальной установке:

  1. Campfire устанавливается на chat.amaros.io с полной интернет-доступностью
  2. WriteBook развертывается на books.amaros.io
  3. Пользовательские приложения (Wiki, Snake game) запускаются на соответствующих доменах

Главное преимущество: приложения доступны в интернете и могут быть поделены с другими пользователями.


Управление Docker-образами и GitHub интеграция

Публикация контейнеров в реестры

AI-кодирование (Vibe-coding) приложений создает Docker-образы, которые должны быть загружены в публичный реестр (GitHub Container Registry) для использования в облаке. Процесс:

  1. Образы генерируются AI моделью (например, Claude/Kimi)
  2. Образы отправляются на GitHub через CLI
  3. Репозитории приватные по умолчанию — требуется изменение видимости на public в Package Settings

Интересный момент: GitHub CLI не поддерживает изменение видимости пакетов через команду, требуя ручного взаимодействия с веб-интерфейсом.


Мониторинг и обновления

Панель управления ONCE

ONCE обеспечивает полный мониторинг всех запущенных приложений:

  • Использование CPU и памяти для каждого приложения
  • Трафик и активность приложений
  • Просмотр логов (команда G) — позволяет видеть логи приложения в реальном времени
  • Бот-активность — системы видят попытки автоматизированных сканеров (например, Chrome 146)

Система обновлений

ONCE автоматически проверяет обновления приложений (по умолчанию раз в день). Пользователь может:

  • Вручную проверить обновления (команда U)
  • Перезагрузить приложение без потери данных
  • Переустановить приложение, если обновление не срабатывает

Процесс обновления использует механизм проверки здоровья — приложение считается готовым только после получения ответа 200 OK на запрос /up.


Практические примеры и демонстрация

Полный жизненный цикл приложения

Демонстрация охватывает:

  1. Локальную разработку с использованием AI-кодирования (Vibe-coding)
  2. Создание одного выстрела (one-shot) — когда AI-модель создает полностью функциональное приложение с первой попытки
  3. Развертывание в облаке на Hetzner сервере с публичными доменами
  4. Обновление и улучшение приложений (например, изменение цветовой схемы Snake game на "Lumen Industries", исправление ошибок)
  5. Управление версиями контейнеров в GitHub

Вызовы при использовании AI-кодирования

  • Не все приложения успешно компилируются с первой попытки (один из примеров Wiki не работал на первый раз)
  • AI-модели требуют указания деталей, таких как обязательность 200 OK ответа на /up endpoint
  • Отладка может потребовать использования инструментов, таких как Playwright CLI для дебага веб-приложений

Ключевые характеристики и преимущества

Простота развертывания

  • Одна команда curl для установки
  • Автоматическое обнаружение системы и зависимостей
  • Отсутствие сложной конфигурации

Масштабируемость

  • Поддержка любого стека технологий (Ruby on Rails, Go, HTML5, etc.)
  • Управление несколькими приложениями на одной машине/сервере
  • Развертывание от локальной машины до облака без изменения процесса

Мониторинг и надежность

  • Единая панель управления для всех приложений
  • Zero-downtime обновления благодаря механизму проверки здоровья
  • Полная история логов и мониторинг ресурсов

Интеграция с современным развитием

  • Идеальная платформа для AI-кодирования — развертывание экспериментов за минуты
  • Автоматизация сборки и развертывания Docker-контейнеров
  • Интеграция с GitHub для управления контейнерами

Заключение

ONCE представляет собой полностью сформировавшийся сервер приложений, который радикально упрощает развертывание и управление веб-приложениями как на локальных машинах, так и в облаке. Платформа становится идеальной средой для AI-кодирования, позволяя разработчикам и AI-моделям быстро создавать, тестировать и развертывать приложения.

Преимущества подхода ONCE:

  • Минимальная кривая обучения — достаточно одной команды и выбора приложения
  • Отсутствие vendor lock-in — любой Docker-образ может быть развернут
  • Производственная готовность — встроенный мониторинг, логирование и управление ресурсами
  • Идеален для экспериментов — быстрое развертывание множества приложений

ONCE переопределяет, как разработчики могут развертывать и управлять приложениями в эпоху AI-кодирования, делая процесс доступным даже для тех, кто не специалист в DevOps.

🧾 Транскрипт (формат)

Once is an easy way to run multiple dockerized web applications on your local laptop, on your closet server, in the cloud, or on-prem hardware. We originally built it to make it easy to host WriteBook, Campfire, and Fizzy on a single machine, but it turns out it is a wonderful general platform for running any kind of web applications. And now that producing these web applications has never been easier. Thanks to the help of AI, it becomes the perfect platform to deploy all your Vibe-coded experiments on and having a single place to monitor them all, see if they're throwing arrows, if you are having capacity problems on that server, and of course also taking backups and updating those web applications without suffering any downtime. So let's have a look at what Once can do, first with our own applications, and then a handful of Vibe-coded example. Let's go.

So this is my local Umachi machine where we will set up Once first, and then after that I'll show you how to set it up on a VM in the cloud. So let's get going here. The first thing we're going to do is we're going to install Once. You're going to do this with the curl fizzle on the get.once.com domain and piping that into Bash. Now this is going to go pretty quick because I already had it installed, but if you didn't, it will auto-detect your system, and set it up. All you need is to have Docker installed, and if you don't have that installed on Linux machine, it'll even install you for you. But here you see the setup as it is when you have not run Once on that machine before. You will be offered to choose one of the default applications that we ship.

We have our three stock applications, Campfire, that's a chat app, Fizzy, it's a Kanban board, and WriteBook is a book for sharing your manuals, and what else have you. We use it for the Umachi manual, for example, and other things like that. And then, of course, you can install a custom Docker image, too. But let's start with installing Campfire first. So, the first thing you're going to have to enter here is a host name, and I'm just going to put it on chat.localhost, that will install it locally here, and we can test it out in a second. It's going to pull down the Docker image from our repository, and bam! Here you see the main control panel for Once. You'll see up top that we have the basis of the machines, all the CPUs, the memory, and the disk that is available to run these applications on, and then below that you have each individual application.

But if I hop in here in a browser, and I go to chat.localhost, you'll see the application is ready to run. Now, I can fill this out here, and just do my name, my email address, and a very, very secret password, and boom! I am ready to chat. Now, how easy was that? How easy was that to get going with a new installation of Campfire on your local setup? That was very easy, but that is not really the magic. The magic comes in when you want to run multiple applications. So, let's add another one here. I'll hit N for new app, and I will choose the right book, and we're just going to do, let's say, books.localhost.com. I'm going to hit install. It's going to do the same little dance, and in a second here, boom! I'm going to have my books.localhost.com. It shares a very similar looking signup as we have for Campfire, but if I jumped in here, you can see everything is set up, ready to go.

There's a stock manual with explanations about how to use WriteBook, or we can start a brand new book, like the ONES manual, for example. I will definitely be creating one of those, and off you go. We have two applications running side-by-side here on localhost, ready to roll. We can also set up Fizzy, of course. Do another application here. Pick Fizzy, and we're going to do Fizzy.localhost. Once we install that, I'll show you something interesting. Now, the thing about both Campfire and WriteBook is it does not need any external services, but that's not quite true with Fizzy. If we go to Fizzy, Fizzy.localhost, you'll see it asks for your email address. Because Fizzy uses email, you'll actually have to configure the SMTP setup. You can go in under S for settings, and then you can go down to E for email, and then you can set up your SMTP server.

So if you fill this in with your SMTP server, Postmark, or whatever, you'll be able to send email from Fizzy, too. So these are the three basic stock applications, but we can also make new applications. And that's what I think is really fascinating about this setup at once. It's great for these prepackaged Docker applications, which, by the way, can have any type of backend. These three here, WriteBook, Campfire, and Fizzy, were all programmed in Ruby on Rails. Ruby on Rails is set up by default to have all the amenities needed to run on ones, but you can run on anything. You don't have to use Ruby on Rails. We could use, for example, Go. So I like to bytecode some of these apps. So if we jump over here and see a preparation I've made for Kimi K25 on Fireworks, let's create a simple wiki in Go.

It should use SQLite, be packaged with Docker, store DB files in storage, and respond to /op with 200.OK. That's how one knows that the application is ready to serve new requests, which is quite important, because on updates it uses that to know when to switch over so that you don't drop any requests in midair. And we're also going to support these links. Then actually, let's also say that it should push all of this to GitHub at dhh/oneswikiwiki. So it's going to cook on that for a second. It does not take very long for Kimi to cook. Kimi is incredibly quick when it runs on fireworks. 200 tokens per second is easily seen. But let's make it even more fun. Let's make two applications at the same time. Because I also want to show you that you don't even have to have a dynamic application.

You can make these wonderful little single HTML file applications as well, like this basic snake game that I'm instructing Kimi to have a go at. Make sure it works in the first try. Yes. And then also push it to GitHub under dhh/snakegame. And the reason we're going to push it to GitHub when we're done with this setup is that we need a public place to host the containers when we want to pull them down and set them up. So let's have that cook as well. Kimi is working on our Go application. And do you know what? While these two Kimis are cooking, maybe we should try to set it up in the cloud as well. And we can use this Hetzner server that I have configured for the purpose. It is just a basic Hetzner VM. I think it's actually running Ubuntu on the back end. And this is the same command as you would run locally on a Linux machine.

You're going to run curl physical to get once.com, pipe it into bash. So let's do that now. I will say I have pre-cooked a little bit here, which is that this Hetzner VM, the IP, I've added to my Cloudflare setup. And I've pointed a wildcard domain at it so that we have DNS. And I'll show you how that works in just one second. But let's let it run. Of course, again, it goes quite quick. It would have to download in your case, but it downloads fast as well. So we can start with the same thing. So we can set up Campfire, and this time, instead of setting it up on localhost, I am going to set up chat on this other domain I have, amaros.io. That's the one I have pointed, star.amaros.io from Cloudflare onto this VM. And we hit install here. It's going to pull it down, and it's going to start it up. And then we can hop over here into our browser and see if we had chat.amaros.io.

Once it's done verifying and booting everything up. There we go. Let's see. Boom. We have the same Campfire setup. It's, of course, a brand new instance with a brand new database. So I'm going to set it up once more with the same kind of credential setup here and the very secret password. And now you have an application that is actually live on the internet webs. And you can share that with anyone, and you can get going. Again, as we did when we were local, we can set up multiple applications here. We can do these books.amaros.io and install that and set it up. And while that is cooking, let's go back to our Kimmies here and see that the wiki wiki is done, and it has been published to this domain here. Let's see what that looks like. It all looks good to me. I'm not going to even review any of it at all.

What I am going to review, though, is whether the package for this thing has been pushed. I can see that it has not. So let's ask it to push a package. Push the docker image to GitHub to GCR. Hopefully, you can figure out how to do that. We need to do one little thing here after it is done cooking, which is that we need to give it permission to go public with this. And apparently, you can't do that through the GitHub CLI, which is a little bit annoying. But while it's building that, let's see if the snake game is done. It is also done. And if I go back here, where have it pushed it? It has pushed it to snake game. It's just going to have that index HTML thing. We actually need to do the same thing here as we were doing the other thing. Push the docker image to GCR. And then let's see if we're done with that. No, it's still pushing. Here you'll see something interesting, by the way.

Three visitors already? Yeah. Because as soon as you put something like this online, there's a bunch of bots that'll start hitting it. But what's neat with this setup, too, is that you can see all the different apps that you have running, how much CPU they're taking up, how much memory they're consuming, and then also the traffic. But you can do more than that. We can hit G when we're on one of these apps, like on the chat app. If we hit G here, you can see the logs. So if we go back to our little chat app here and say, "Hello world," boom. You can see the logs going on here. It's cooking. This is our Chrome 146 doing its work here. All right. It is now live on the Ones Wiki Wiki. I mean, this is all live. This is all vibe coded. So who the hell knows if it's just going to work on the first go. But I am going to try. So we're going to copy this link or this URL to the setup.

Should we just set it up live on Headstone? I think we should. Let's just run with scissors here. We're going to do a custom Docker image. We're going to paste this in. We're going to set up this Wiki. And we're going to host it on just wiki.amarros.io. And nope, it failed. That was exactly what I was talking about earlier. The registry is unauthorized. We have to go back here to our packages. See that it has pushed both of these. So on the Ones Wiki Wiki, you can see it's private. We've got to go to package settings. We've got to go down to visibility. This is, of course, hidden behind my little head here. So let's just swap this one over. And change visibility. We're going to make it public. And then we're going to type Ones Wiki Wiki. And now the package is going to be public.

So if we hop back on our Ones installation in Headstone, we should actually be able to hit next and then host it on that wiki.amarros.io. And then let's see if it's going to cook correctly this time. Yep, it's downloading. It's starting. Now, of course, let's see if it one-shotted this. Kimi is often quite good at one-shotting, but maybe I should have given the instructions to test what it was setting up. Because while it's starting here, I'm actually going to try to do the same thing with the snake game. We go back to packages here, hopping back over one more time, packages. We had snake game that's private. Go to package settings. Go down to change visibility. Make it public on snake game. And then we can try to run that snake game locally. Because if I jump over here, yeah, I think there's something wrong with that wiki one. Let's fix that in a second.

And then we will start by creating the new application here for the snake game locally. We are going to have to copy that over from the snake game where it said it was going to live. It was going to live right here. Alrighty. The latest snake game. Hop back. Post in to snake.localhost. And install that. That went pretty fast. Snake.localhost. Boom. Here is the snake game. And it actually worked as a one-shot. Last time I tried this, it did not work. And you can see there is actually a problem here. When it restarts, it doesn't want to work. But I could just reload and off we go. Now, let me actually show you how to do the update for this game. When you want to continue to work on something, it's quite nice that if we hop over to the snake game, we could do something like, we can restart the game when you're dead, fix that, and change the color scheme to Lumen Industries.

And then push the new container image. All right. You cook along on that, and let's see what's going on here. It failed to become healthy. So that's probably that it did not get that /up thing. It seems like /up is not working. It needs to return 200 okay for it to work with once. Let's see if it can fix it on a second go here. Meanwhile, our snake game is done, and the new image has been pushed. So we can go back here. Under snake, then go to settings. We can hit S. And then we can go to updates, or you can just hit U. It's automatically updating as well. I think it's just once a day. But we can also just check for updates now. Already running the latest version. I don't think it did push it. Did? Blah, blah, blah, blah, blah. Push, push, push. No, it did. Well, let's see what's going on. Let me go ahead and reload it. Nope. We're not running the latest one. So let's try one more time.

Maybe it took a while for it to propagate. Already running the latest version. Let's see what it says here under the packages that we have. We have the snake game package. And it just tagged it one minute ago. So that should actually be correct. Snake game latest. Already running the latest version. Let's try to set it up on Hesner as well with that one. If I go back here and I, instead of doing the once wiki, we're going to do the snake game. And we're going to host it on snake.mros.io. I'm going to download that and see if we get the latest version. View and manage all versions here. No, it was pushed correctly, it seems, for the snake game. Let's see if we got the snake game on Mario OS. Oh, it was. And here we have our Lumen Industries. Look. I'm not quite sure that's Lumen Industries. But it is different and it does work.

Let's see if it fixed the bug where if you hit the wall, you can restart. We're complete. Press any button to continue. Oh, it did fix that. So this is the wonders of Vibe coding. One step at a time and we move forward. Let's hop back here and see if we could get that wiki to go. We fixed it up. Returns okay. Blah, blah, blah. It's now live. Okay. Let's check if that can now be set up. We have the customer image again. It was on. Let's see what it was on. It was on this URL for the latest. Let's see if we can make it fresh from here. Wiki. We're just going to wait to iOS install. You can download that new image and let's see if there's any magic. If the agent gods are with us today. And then let's hop back here and see why this one might not be willing to update. So hop back in under settings. We do the updates. We check for updates.

And if that doesn't work, which I don't quite get why it doesn't, but we can then show how you can remove something. So we can do a fractions. You can stop it. Now you see that one is stopped. Then we do a fractions again. We do remove. And then we're going to remove that application and that data. And I can add it once more time as a custom image here. Hop back over to this. Copy the URL again. Hop back there. Paste it in and sneaky. Let's just call it something else and we have it unique. Well, no. It was on localhost. And then install that. So we should have the same game as the Lumen Industries set up here. Snakey.localhost. Snakey. Snakey, I called it. Interesting. Although this is a nice way to show that you get the Kamal proxy style, beautifully designed 404 error messages when you get it wrong here. And here we have the correct game.

And we're running our Lumen Industries snake game locally. Great. All right. The last setup here. We are not getting that WikiWiki to go. Why are we not getting that WikiWiki to go? Should we try to see if we can get it running locally? What's the command to run locally? And then we can at least see if there is any setup where we can run this locally. I want to run it from Docker. All right. Here's the Docker command to running it locally. Well, it's going to try to pull the-- actually, let's just try that. That's going to pull it live. And then we'll see if the issue was still something with that up command. Localhost-- well, there's not really much going on here. Maybe that's why it's crapping out. Oh, it does give us an OK. But did it actually give us a 200 OK? Let's see if that's the case. Oh, it did give us a 200 OK.

So maybe that's the same issue as we were having earlier with it not updating because it does look like an update. But what it did not look like was it did not look like we had a functioning Wiki. Let's ask it about that. It doesn't look like anything is working. Just the white screen. Can you use Playwright CLI to debug it? It's running on localhost 8080. All right. We can let it cook here. Good npx install, blah, blah, take a screenshot. We're just going to let it allow all the things. This is the fun magic of working with AI. When I ran a test on this earlier, I did get it to just one shot my little wiki wiki here. You might have seen those artifacts were still in the GitHub repository. In fact, maybe we can just grab one of those while it is trying to figure out what went wrong. I think we had them here on the packages. I had a once wiki.

Let's try that one and see if we can get that going instead. I'm going to hop over here. Let's do it on Hetzner. We're going to just do once wiki and set that up. Then we're going to do just WMROS.IO. Installing that, downloading it, and setting it up. Then if that one works, we should be able to go to WMROS.IO. See that running. Boom! Here was the one-shotted wiki that I did before I started this video. This one works at least. Now, of course, you can use any model. Maybe if you'd used a different model, it would have had a higher chance of getting a one-shot. It is still cooking here. The image is rebuilt. Blah, blah, blah. What was wrong? Oh, it did find some errors. And now it's starting it up and based on the find. Anyway, we can actually also install that wiki that was working on localhost here. So let's do that as well. We had that as -- did I have that on here? No.

Actually, it was -- what's the latest we needed for this one? It was just on wiki. Let me delete all of this. Boom. Off we go. We're going to do it on wiki.localhost. Download that image. Now we've got that one up and running, wiki.localhost. And here we have it running on localhost. So we have one, two, three, four, five different apps running. One of them is a Go app. One of them is a plain HTML rep running in Nginx. And three of them are the stock Ruby on Rails apps that we have. And on Hetzner, we have a handful of applications as well. And we still have Kimmy trying to fix its second attempt at a one shot wiki wiki. I'm sure it's going to get it at some point. But sorry, Kimmy, we're not going to let you finish. This is it. This is a brief demonstration of the new ONCE application server. I hope you have fun with it.

I hope you give Fizzy, WriteBook, and Campfire a try now that it's so easy to set up. And I hope you have some great vibe coding experiments. Enjoy. See you.